/*
 * $Id: handler.cpp 315 2010-03-25 23:57:03Z cmtonkinson@gmail.com $
 *
 * This file is part of the Symphony project <http://code.google.com/p/symphonymud/>
 * Copyright 2005-2010 Chris Tonkinson <cmtonkinson@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <vector>
#include "avatar.h"
#include "color-string.h"
#include "commandTable.h"
#include "commandTable-default.h"
#include "display.h"
#include "handler.h"
#include "symphony.h"
#include "world.h"

/************************************** BASE CLASS HANDLE METHOD **************************************/
Handler::Handler( Creature* creature ) {
  this->creature( creature );
  this->commandTable( &(Commands::Instance()) );
  return;
}

bool Handler::handle( const std::string& text ) {
  Command* command = NULL;
  std::string input = text;
  std::vector<std::string> args;
  short max_num_args = 0;
  short negative_args = 0;

  /* '!' is a shortcut for 'execute the previous command again.' */
  if ( input == "!" ) {
    input = lastInput();
  } else {
    lastInput( input );
  }

  /* Search the CommandTable for a match of the first token in `input`. */
  if ( ( command = commandTable()->find( input ) ) == NULL ) {
    creature()->send( "Huh?" );
    return false;
  }

  /* Make sure that the Creature is allowed to execute the
   * specified Command.  Assert:
   *   1) That the Creature has a high enough level
   *   2) Thta the Command is enabled
   *   3) Kirby Wuz Here
   */
  if ( creature()->level() < command->level()
    || !command->enabled() ) {
    creature()->send( "Huh?" );
    return false;
  }

  /* We need to make sure that the Creature is in one of the
   * allowed positions (sleeping, sitting, standing, etc) to
   * execute the Command.
   */
  if ( ( creature()->position() & command->allowedPositions() ) != creature()->position() ) {
    creature()->send( "You can't do that while %s.", creature()->positionToString() );
    return false;
  }

  /* A Command has a std::set<short> called _arguments.  If this set contains positive
   * numbers (this is considered the general case) then we Regex::split() on the largest
   * of those numbers and then perform a check to ensure that the actual number of
   * arguments captured is valid.  There are two special cases:
   *
   * 1) When the first argument split() is empty, then no arguments were provided for the
   *    Command.  In this case, we assert that 0 is a valid number of arguments for the
   *    Command.  And example of this is the `look` Command:
   *        `look`         (zero arguments)
   *        `look chris`   (one argument)
   *    In the first case here, `look` is executed with no arguments, so we make a check
   *    that 0 is in Command::_arguments.
   *
   * 2) When we find a negative number (call it N) in _arguments, then the given Command
   *    expects a certain number of exact arguments followed by an arbitrary string.  In
   *    this case, the number of exact arguments is -(N+1) and the remaining text is
   *    part of the arbitraty string.  Examples are:
   *        `say hello there`                         (-1 arguments)
   *        `tell chris Hello there.`                 (-2 arguments)
   *        `restring sword shortname a neat sword`   (-3 arguments)
   *    So `say` expects only an arbitrary string.  `tell` expects one argument (the name
   *    of the target) and then an arbitrary string.  And so on.
   */

  // Get the largest number of accpted arguments and split()
  max_num_args = *command->arguments().rbegin();
  args = Regex::split( input, max_num_args );
  // This is special case #1 from above...
  if ( args[0].empty() ) {
    if ( command->arguments().find( 0 ) == command->arguments().end() ) {
      creature()->send( command->printSyntax() );
      return false;
    }
  // This is special case #2 from above...
  } else if ( ( negative_args = *command->arguments().begin() ) < 0 ) {
    args = Regex::split( input, -(negative_args+1) );
  // This is the general case...
  } else {
    if ( command->arguments().find( args.size() ) == command->arguments().end() ) {
      creature()->send( command->printSyntax() );
      return false;
    }
  }
  // Execute the Command...
  return command->execute( creature(), args );
}

bool Handler::handle( void ) {
  return handle( ((Avatar*)creature())->getInput() );
}

/************************************** NPC HANDLER **************************************/
void NpcHandler::activate( void ) {
  return;
}

void NpcHandler::deactivate( void ) {
  return;
}

bool NpcHandler::handle( Creature* creature, const std::string& text ) {
  Command* command = NULL;
  std::string input = text;

  // Find the command...
  if ( ( command = Commands::Instance().find( input ) ) == NULL ) {
    creature->send( "Huh?" );
    return false;
  }

  // Just to be sure...
  if ( command->playerOnly() ) {
    if ( !creature->type( TYPE_AVATAR ) ) {
      creature->send( "huh?" );
      return false;
    }
  }
/*
  // Execute the command (if able to do so)...
  if ( !Commands::Instance().execute( creature, command, input ) ) {
    creature->send( "Huh?" );
    return false;
  }
*/
  return true;
}

std::string NpcHandler::prompt( void ) {
  return std::string();
}

/************************************** LOGIN (BANNER) HANDLER **************************************/
void SendBannerHandler::activate( void ) {
  creature()->send( prompt() );
  creature()->replaceHandler( new GetNameHandler( creature() ) );
  return;
}

void SendBannerHandler::deactivate( void ) {
  return;
}

bool SendBannerHandler::handle( void ) {
  return true;
}

std::string SendBannerHandler::prompt( void ) {
  return "\n\n\n\n\n{RS{Gy{Ym{Bp{Mh{Co{Rn{Gy{W!!{x\n\n\n\n\n";
}

/************************************** LOGIN (NAME) HANDLER **************************************/
void GetNameHandler::activate( void ) {
  return;
}

void GetNameHandler::deactivate( void ) {
  return;
}

bool GetNameHandler::handle( void ) {
  Avatar* avatar = (Avatar*)creature();
  std::string input = ColorString(avatar->getInput()).stripColor();
  input = Regex::trim( input.substr( 0, input.find_first_of(' ') ) );

  // Check to make sure that name isn't already signed in...
  if ( World::Instance().findAvatar( input ) ) {
    avatar->send( "Sorry - they're already signed in.\n" );
    avatar->disconnected( true );
    return false;
  }

  // Figure out whether or not the given name already exists...
  avatar->identifiers().shortname( Regex::lower(input) );
  avatar->identifiers().addKeyword( avatar->identifiers().shortname() );
  if ( avatar->load() ) {
    creature()->replaceHandler( new GetPasswordHandler( creature() ) );
    return true;
  } else {
    /* This block will eventually push a new handler for creation; for now it just d/c's */
    creature()->send( "Invalid username.\n" );
    avatar->disconnected( true );
    return false;
  }
}

std::string GetNameHandler::prompt( void ) {
  return "Name: ";
}

/************************************** LOGIN (PASSWORD) HANDLER **************************************/
void GetPasswordHandler::activate( void ) {
  creature()->send( "\n" );
  return;
}

void GetPasswordHandler::deactivate( void ) {
  return;
}

bool GetPasswordHandler::handle( void ) {
  Avatar* avatar = (Avatar*)creature();
  std::string input = avatar->getInput();
  estring fd = avatar->socket()->getFd();
  input = Regex::trim( input.substr( 0, input.find_first_of(' ') ) );
  CmdLook look;
  std::vector<std::string> look_args( 1 );

  if ( avatar->checkPassword( input ) ) {
    World::Instance().bigBrother( avatar, ADMIN_BIGBRO_LOGINS, "%s has logged in from %s.", creature()->identifiers().shortname().c_str(), avatar->socket()->getIP().c_str() );
    World::Instance().playerLog( NOTICE, LOG_PLAYER, "%s (%lu) logged in from %s", creature()->identifiers().shortname().c_str(), creature()->ID(), avatar->socket()->getIP().c_str() );
    World::Instance().removeAvatar( fd );
    World::Instance().insert( avatar );
    avatar->status( CONNECTED );
    creature()->replaceHandler( new InputHandler( creature() ) );
    creature()->send( "\nWecome back!\n" );
    look.execute( creature(), look_args );
    return true;
  } else {
    creature()->send( "That password is invalid.\n" );
    avatar->disconnected( true );
    return false;
  }
}

std::string GetPasswordHandler::prompt( void ) {
  return "Password: ";
}

/************************************** NOTE (SUBJECT) HANDLER **************************************/
void NoteGetSubjectHandler::activate( void ) {
  creature()->send( "\n" );
  return;
}

void NoteGetSubjectHandler::deactivate( void ) {
  return;
}

bool NoteGetSubjectHandler::handle( void ) {
  Avatar* avatar = (Avatar*)creature();
  std::string input = ColorString(avatar->getInput()).stripColor();
  avatar->note()->subject( input );
  avatar->composing( Avatar::Composing_Note );
  Handler* h = new TeditHandler( creature() );
  h->getState()["vector"] = (void*)(new std::vector<std::string>());
  h->getState()["name"] = (void*)(new std::string("Note Editor"));
  h->getState()["pointer"] = (void*)avatar->note()->bodyp();
  creature()->replaceHandler( h );
  creature()->send( "Type `cancel` to abandon your note or `send` to finish it." );
  return true;
}

std::string NoteGetSubjectHandler::prompt( void ) {
  return "Subject: ";
}

/************************************** NOTE (SEND) HANDLER **************************************/
void NoteSendHandler::activate( void ) {
  creature()->popHandler();
  return;
}

void NoteSendHandler::deactivate( void ) {
  Avatar* avatar = (Avatar*)creature();
  avatar->composing( Avatar::Composing_Nothing );
  avatar->note()->save();
  World::Instance().boards()[avatar->board()]->notes().insert( std::make_pair( avatar->note()->ID(), avatar->note() ) );
  avatar->note( NULL );
  avatar->send( "Your note has been sent." );
  return;
}

bool NoteSendHandler::handle( void ) {
  return true;
}

std::string NoteSendHandler::prompt( void ) {
  return "";
}

/************************************** NOTE (CANCEL) HANDLER **************************************/
void NoteCancelHandler::activate( void ) {
  creature()->popHandler();
  return;
}

void NoteCancelHandler::deactivate( void ) {
  Avatar* avatar = (Avatar*)creature();
  avatar->composing( Avatar::Composing_Nothing );
  avatar->note()->destroy();
  avatar->note( NULL );
  avatar->send( "Your note has been trashed." );
  return;
}

bool NoteCancelHandler::handle( void ) {
  return true;
}

std::string NoteCancelHandler::prompt( void ) {
  return "";
}

/************************************** MAIN HANDLER **************************************/
void InputHandler::activate( void ) {
  commandTable( &(Commands::Instance()) );
  return;
}

void InputHandler::deactivate( void ) {
  return;
}

std::string InputHandler::prompt( void ) {
  if ( ((Avatar*)creature())->who( WHO_AFK ) ) {
    return "\n\n{x[{YAFK{x] ";
  }
  return "\n\n{x[{CSymphony{x] ";
}

/************************************** AEDIT HANDLER **************************************/
void AeditHandler::activate( void ) {
  commandTable( &(AeditCommands::Instance()) );
  ((Avatar*)creature())->who( WHO_BUSY, true );
  ((Avatar*)creature())->mode( MODE_AEDIT );
  World::Instance().bigBrother( creature(), ADMIN_BIGBRO_MODES, "%s has entered area editing mode.", creature()->identifiers().shortname().c_str() );
  return;
}

void AeditHandler::deactivate( void ) {
  creature()->send( "Goodbye!\n" );
  ((Avatar*)creature())->who( WHO_BUSY, false );
  ((Avatar*)creature())->mode( MODE_NONE );
  World::Instance().bigBrother( creature(), ADMIN_BIGBRO_MODES, "%s has left area editing mode.", creature()->identifiers().shortname().c_str() );
  return;
}

std::string AeditHandler::prompt( void ) {
  char buffer[MAX_BUFFER];
  sprintf( buffer, "\n\n{W[{cAedit {x- {G%s{W] ", creature()->aedit()->name().c_str() );
  return buffer;
}

/************************************** MEDIT HANDLER **************************************/
void MeditHandler::activate( void ) {
  commandTable( &(MeditCommands::Instance()) );
  ((Avatar*)creature())->who( WHO_BUSY, true );
  ((Avatar*)creature())->mode( MODE_MEDIT );
  World::Instance().bigBrother( creature(), ADMIN_BIGBRO_MODES, "%s has entered mob editing mode.", creature()->identifiers().shortname().c_str() );
  return;
}

void MeditHandler::deactivate( void ) {
  creature()->send( "Goodbye!\n" );
  ((Avatar*)creature())->who( WHO_BUSY, false );
  ((Avatar*)creature())->mode( MODE_NONE );
  World::Instance().bigBrother( creature(), ADMIN_BIGBRO_MODES, "%s has left mob editing mode.", creature()->identifiers().shortname().c_str() );
  return;
}

std::string MeditHandler::prompt( void ) {
  char buffer[MAX_BUFFER];
  sprintf( buffer, "\n\n{W[{cMedit {x- {G%lu{W] ", creature()->medit()->vnum() );
  return buffer;
}

/************************************** OEDIT HANDLER **************************************/
void OeditHandler::activate( void ) {
  commandTable( &(OeditCommands::Instance()) );
  ((Avatar*)creature())->who( WHO_BUSY, true );
  ((Avatar*)creature())->mode( MODE_OEDIT );
  World::Instance().bigBrother( creature(), ADMIN_BIGBRO_MODES, "%s has entered object editing mode.", creature()->identifiers().shortname().c_str() );
  return;
}

void OeditHandler::deactivate( void ) {
  creature()->send( "Goodbye!\n" );
  ((Avatar*)creature())->who( WHO_BUSY, false );
  ((Avatar*)creature())->mode( MODE_NONE );
  World::Instance().bigBrother( creature(), ADMIN_BIGBRO_MODES, "%s has left object editing mode.", creature()->identifiers().shortname().c_str() );
  return;
}

std::string OeditHandler::prompt( void ) {
  char buffer[MAX_BUFFER];
  sprintf( buffer, "\n\n{W[{cOedit {x- {G%lu{W] ", creature()->oedit()->vnum() );
  return buffer;
}

/************************************** PEDIT HANDLER **************************************/
void PeditHandler::activate( void ) {
  commandTable( &(PeditCommands::Instance()) );
  ((Avatar*)creature())->who( WHO_BUSY, true );
  ((Avatar*)creature())->mode( MODE_PEDIT );
  World::Instance().bigBrother( creature(), ADMIN_BIGBRO_MODES, "%s has entered player editing mode.", creature()->identifiers().shortname().c_str() );
  return;
}

void PeditHandler::deactivate( void ) {
  creature()->send( "Goodbye!\n" );
  ((Avatar*)creature())->who( WHO_BUSY, false );
  ((Avatar*)creature())->mode( MODE_NONE );
  World::Instance().bigBrother( creature(), ADMIN_BIGBRO_MODES, "%s has left player editing mode.", creature()->identifiers().shortname().c_str() );
  return;
}

std::string PeditHandler::prompt( void ) {
  char buffer[MAX_BUFFER];
  sprintf( buffer, "\n\n{W[{cPedit {x- {G%s{W] ", creature()->pedit()->identifiers().shortname().c_str() );
  return buffer;
}

/************************************** REDIT HANDLER **************************************/
void ReditHandler::activate( void ) {
  commandTable( &(ReditCommands::Instance()) );
  ((Avatar*)creature())->who( WHO_BUSY, true );
  ((Avatar*)creature())->mode( MODE_REDIT );
  World::Instance().bigBrother( creature(), ADMIN_BIGBRO_MODES, "%s has entered room editing mode.", creature()->identifiers().shortname().c_str() );
  return;
}

void ReditHandler::deactivate( void ) {
  creature()->send( "Goodbye!\n" );
  ((Avatar*)creature())->who( WHO_BUSY, false );
  ((Avatar*)creature())->mode( MODE_NONE );
  World::Instance().bigBrother( creature(), ADMIN_BIGBRO_MODES, "%s has left room editing mode.", creature()->identifiers().shortname().c_str() );
  return;
}

std::string ReditHandler::prompt( void ) {
  char buffer[MAX_BUFFER];
  sprintf( buffer, "\n\n{W[{cRedit {x- {G%lu{W] ", creature()->room()->vnum() );
  return buffer;
}

/************************************** SEDIT HANDLER **************************************/
void SeditHandler::activate( void ) {
  commandTable( &(SeditCommands::Instance()) );
  ((Avatar*)creature())->who( WHO_BUSY, true );
  ((Avatar*)creature())->mode( MODE_SEDIT );
  World::Instance().bigBrother( creature(), ADMIN_BIGBRO_MODES, "%s has entered social editing mode.", creature()->identifiers().shortname().c_str() );
  return;
}

void SeditHandler::deactivate( void ) {
  creature()->send( "Goodbye!\n" );
  ((Avatar*)creature())->who( WHO_BUSY, false );
  ((Avatar*)creature())->mode( MODE_NONE );
  World::Instance().bigBrother( creature(), ADMIN_BIGBRO_MODES, "%s has left social editing mode.", creature()->identifiers().shortname().c_str() );
  return;
}

std::string SeditHandler::prompt( void ) {
  char buffer[MAX_BUFFER];
  sprintf( buffer, "\n\n{W[{cSedit {x- {G%s{W] ", creature()->sedit()->name().c_str() );
  return buffer;
}

/************************************** TEDIT HANDLER **************************************/
void TeditHandler::activate( void ) {
  commandTable( &(TeditCommands::Instance()) );
  ((Avatar*)creature())->who( WHO_BUSY, true );
  creature()->send( "Welcome to the Symphony Text Editor.\n" );
  return;
}

void TeditHandler::deactivate( void ) {
  std::vector<std::string>* v = (std::vector<std::string>*)getState()["vector"];
  std::string* s = (std::string*)getState()["name"];
  ((std::string*)getState()["pointer"])->assign( Regex::implode( "\n", *v ) );
  delete v;
  delete s;
  getState().clear();
  creature()->send( "You've left the Symphony Text Editor.\n" );
  return;
}

std::string TeditHandler::prompt( void ) {
  char buffer[MAX_BUFFER];
  sprintf( buffer, "\n\n{W[{cCurrently Editing: {C%s{W] ", ((std::string*)getState()["name"])->c_str() );
  return buffer;
}

